package com.karaku.karaku_collector.common.http;

import android.text.TextUtils;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import java.lang.reflect.Modifier;
import java.lang.reflect.Type;

/**
 * Created by guoping on 2017/4/24.
 */

public class JsonFinder {

    private static Gson sGson = new GsonBuilder()
            .excludeFieldsWithModifiers(Modifier.PRIVATE, Modifier.PROTECTED, Modifier.STATIC)
//            .excludeFieldsWithoutExposeAnnotation()
            .create();

    private JsonElement mJson;

    public static void setGson(Gson gson) {
        sGson = gson;
    }

    public static Gson getGson() {
        return sGson;
    }

    public static <T> T find(String json, String path, Type typeOfT) {
        return new JsonFinder(json).find(path, typeOfT);
    }

    public static <T> T find(JsonElement json, String path, Type typeOfT) {
        return new JsonFinder(json).find(path, typeOfT);
    }

    public JsonFinder(String json) {
        mJson = new JsonParser().parse(json);
    }

    public JsonFinder(JsonElement json) {
        mJson = json;
    }

    public <T> T find(String path, Type typeOfT) {
        JsonElement json = mJson;
        if (json == null) {
            return null;
        }
        Object[] objPath = getPath(path);
        if (objPath == null) {
            return sGson.fromJson(json, typeOfT);
        } else {
            for (int i = 0; i < objPath.length; ++i) {
                Object member = objPath[i];
                Object nextMember = null;
                if (i < objPath.length - 1) {
                    nextMember = objPath[i + 1];
                }
                if (nextMember == null) {
                    return getChild(json, member, typeOfT);
                } else {
                    if (nextMember instanceof String) {
                        json = getChild(json, member, JsonObject.class);
                    } else {
                        json = getChild(json, member, JsonArray.class);
                    }
                }
            }
        }
        return null;
    }

    private <T> T getChild(JsonElement json, Object member, Type typeOfT) {
        if (member instanceof String) {
            if (typeOfT.equals(JsonArray.class)) {
                return (T) json.getAsJsonObject().getAsJsonArray((String) member);
            } else if (typeOfT.equals(JsonObject.class)) {
                return (T) json.getAsJsonObject().getAsJsonObject((String) member);
            } else {
                return sGson.fromJson(json.getAsJsonObject().get((String) member), typeOfT);
            }
        } else {
            if (typeOfT.equals(JsonArray.class)) {
                return (T) json.getAsJsonArray().get((Integer) member).getAsJsonArray();
            } else if (typeOfT.equals(JsonObject.class)) {
                return (T) json.getAsJsonArray().get((Integer) member).getAsJsonObject();
            } else {
                return sGson.fromJson(json.getAsJsonArray().get((Integer) member), typeOfT);
            }
        }
    }

    private Object[] getPath(String path) {
        if (TextUtils.isEmpty(path)) {
            return null;
        }
        String[] names = path.split("\\.");
        Object[] objPath = new Object[names.length];
        for (int i = 0; i < names.length; ++i) {
            String name = names[i];
            if (name.matches("^[\\d+]$")) {
                objPath[i] = Integer.parseInt(name.substring(1, name.length() - 1));
            } else {
                objPath[i] = name;
            }
        }
        return objPath;
    }
}
